home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / amiga / asrc29k.lha / kernel.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-08  |  11.7 KB  |  521 lines

  1. /* Non pre-empting synchronization kernel, machine-independent portion */
  2.  
  3. #define    SUSPEND_PROC    1
  4. #undef    PROCTRACE        1
  5. #undef    PROCLOG        1
  6.  
  7. #if    defined(PROCLOG) || defined(PROCTRACE)
  8. #include <stdio.h>
  9. #endif
  10. #include <dos.h>
  11. #include <setjmp.h>
  12. #include "global.h"
  13. #include "mbuf.h"
  14. #include "proc.h"
  15. #include "timer.h"
  16. #include "socket.h"
  17. #include "daemon.h"
  18. #include "hardware.h"
  19.  
  20. #ifdef    PROCLOG
  21. FILE *proclog;
  22. FILE *proctrace;
  23. #endif
  24. int Stkchk = 0;
  25. struct proc *Curproc;        /* Currently running process */
  26. struct proc *Rdytab;        /* Processes ready to run (not including curproc) */
  27. struct proc *Waittab[PHASH];    /* Waiting process list */
  28. struct proc *Susptab;        /* Suspended processes */
  29. static struct mbuf *Killq;
  30.  
  31. static void addproc __ARGS((struct proc *entry));
  32. static void delproc __ARGS((struct proc *entry));
  33. static unsigned phash __ARGS((void *event));
  34.  
  35. /* Create a process descriptor for the main function. Must be actually
  36.  * called from the main function!
  37.  */
  38. struct proc *
  39. mainproc(name)
  40. char *name;
  41. {
  42.     register struct proc *pp;
  43.  
  44.     /* Create process descriptor */
  45.     pp = (struct proc *)callocw(1,sizeof(struct proc));
  46.  
  47.     /* Create name */
  48.     pp->name = strdup(name);
  49. #ifndef    AMIGA
  50.     pp->stksize = 0;
  51. #else
  52.     init_psetup(pp);
  53. #endif
  54.     pp->output = Console;
  55.  
  56.     /* Make current */
  57.     pp->state = READY;
  58.     Curproc = pp;
  59.  
  60. #ifdef    PROCLOG
  61.     proclog = fopen("proclog",APPEND_TEXT);
  62.     proctrace = fopen("proctrace",APPEND_TEXT);
  63. #endif
  64.     return pp;
  65. }
  66. /* Create a new, ready process and return pointer to descriptor.
  67.  * The general registers are not initialized, but optional args are pushed
  68.  * on the stack so they can be seen by a C function.
  69.  */
  70. struct proc *
  71. newproc(name,stksize,pc,iarg,parg1,parg2)
  72. char *name;        /* Arbitrary user-assigned name string */
  73. unsigned int stksize;    /* Stack size in words to allocate */
  74. void (*pc)();        /* Initial execution address */
  75. int iarg;        /* Integer argument (argc) */
  76. void *parg1;        /* Generic pointer argument #1 (argv) */
  77. void *parg2;        /* Generic pointer argument #2 (session ptr) */
  78. {
  79.     register struct proc *pp;
  80.     int i;
  81.  
  82.     if(Stkchk)
  83.         chkstk();
  84.  
  85.     /* Create process descriptor */
  86.     pp = (struct proc *)callocw(1,sizeof(struct proc));
  87.  
  88.     /* Create name */
  89.     pp->name = strdup(name);
  90.  
  91.     /* Allocate stack */
  92. #ifdef    AMIGA
  93.     stksize += 2000;    /* DOS overhead */
  94. #endif
  95.     pp->stksize = stksize;
  96.     if((pp->stack = (int16 *)malloc(sizeof(int16)*stksize)) == NULL){
  97.         free(pp->name);
  98.         free((char *)pp);
  99.         return NULLPROC;
  100.     }
  101.     /* Initialize stack for high-water check */
  102.     for(i=0;i<stksize;i++)
  103.         pp->stack[i] = STACKPAT;
  104.  
  105.     /* Do machine-dependent initialization of stack */
  106.     psetup(pp,iarg,parg1,parg2,pc);
  107.  
  108.     /* Inherit creator's input and output sockets */
  109.     usesock(Curproc->input);
  110.     pp->input = Curproc->input;
  111.     usesock(Curproc->output);
  112.     pp->output = Curproc->output;
  113.  
  114.     /* Add to ready process table */
  115.     pp->state = READY;
  116.     addproc(pp);
  117.     return pp;
  118. }
  119.  
  120. /* Free resources allocated to specified process. If a process wants to kill
  121.  * itself, the reaper is called to do the dirty work. This avoids some
  122.  * messy situations that would otherwise occur, like freeing your own stack.
  123.  */
  124. void
  125. killproc(pp)
  126. register struct proc *pp;
  127. {
  128.     if(pp == NULLPROC)
  129.         return;
  130.     /* Don't check the stack here! Will cause infinite recursion if
  131.      * called from a stack error
  132.      */
  133.  
  134.     if(pp == Curproc)
  135.         killself();    /* Doesn't return */
  136.  
  137.     /* Close any open sockets */
  138.     freesock(pp);
  139.  
  140.     close_s(pp->input);
  141.     close_s(pp->output);
  142.  
  143.     /* Stop alarm clock in case it's running */
  144.     stop_timer(&pp->alarm);
  145.  
  146.     /* Alert everyone waiting for this proc to die */
  147.     psignal(pp,0);
  148.  
  149.     /* Remove from appropriate table */
  150.     delproc(pp);
  151.  
  152. #ifdef    PROCLOG
  153.     fprintf(proclog,"id %lx name %s stack %u/%u\n",ptol(pp),
  154.         pp->name,stkutil(pp),pp->stksize);
  155.     fclose(proclog);
  156.     proclog = fopen("proclog",APPEND_TEXT);
  157.     proctrace = fopen("proctrace",APPEND_TEXT);
  158. #endif
  159.     /* Free allocated memory resources */
  160.     free(pp->name);
  161.     free(pp->stack);
  162.     free(pp->outbuf);
  163.     free((char *)pp);
  164. }
  165. /* Terminate current process by sending a request to the killer process.
  166.  * Automatically called when a process function returns. Does not return.
  167.  */
  168. void
  169. killself()
  170. {
  171.     register struct mbuf *bp;
  172.  
  173.     if(Curproc != NULLPROC){
  174.         bp = pushdown(NULLBUF,sizeof(Curproc));
  175.         memcpy(bp->data,(char *)&Curproc,sizeof(Curproc));
  176.         enqueue(&Killq,bp);
  177.     }
  178.     /* "Wait for me; I will be merciful and quick." */
  179.     for(;;)
  180.         pwait(NULL);
  181. }
  182. /* Process used by processes that want to kill themselves */
  183. void
  184. killer(i,v1,v2)
  185. int i;
  186. void *v1;
  187. void *v2;
  188. {
  189.     struct proc *pp;
  190.     struct mbuf *bp;
  191.  
  192.     for(;;){
  193.         while(Killq == NULLBUF)
  194.             pwait(&Killq);
  195.         bp = dequeue(&Killq);
  196.         pullup(&bp,(char *)&pp,sizeof(pp));
  197.         free_p(bp);
  198.         if(pp != Curproc)    /* We're immortal */
  199.             killproc(pp);
  200.     }                        
  201. }
  202.  
  203. #ifdef    SUSPEND_PROC
  204. /* Inhibit a process from running */
  205. static void
  206. suspend(pp)
  207. struct proc *pp;
  208. {
  209.     if(pp == NULLPROC)
  210.         return;
  211.     if(pp != Curproc)
  212.         delproc(pp);    /* Running process isn't on any list */
  213.     pp->state |= SUSPEND;
  214.     if(pp != Curproc)
  215.         addproc(pp);    /* pwait will do it for us */
  216.     else
  217.         pwait(NULL);
  218. }
  219. /* Restart suspended process */
  220. static void
  221. resume(pp)
  222. struct proc *pp;
  223. {
  224.     if(pp == NULLPROC)
  225.         return;
  226.     delproc(pp);    /* Can't be Curproc! */
  227.     pp->state &= ~SUSPEND;
  228.     addproc(pp);
  229. }
  230. #endif    /* SUSPEND_PROC */
  231.  
  232. /* Wakeup waiting process, regardless of event it's waiting for. The process
  233.  * will see a return value of "val" from its pwait() call.
  234.  */
  235. void
  236. alert(pp,val)
  237. struct proc *pp;
  238. int val;
  239. {
  240.     if(pp == NULLPROC)
  241.         return;
  242. #ifdef    notdef
  243.     if((pp->state & WAITING) == 0)
  244.         return;
  245. #endif
  246. #ifdef    PROCTRACE
  247.     printf("alert(%lx,%u) [%s]\n",ptol(pp),val,pp->name);
  248.     fflush(stdout);
  249. #endif
  250.     if(pp != Curproc)
  251.         delproc(pp);
  252.     pp->state &= ~WAITING;
  253.     pp->retval = val;
  254.     pp->event = 0;
  255.     if(pp != Curproc)
  256.         addproc(pp);
  257. }
  258.  
  259. /* Post a wait on a specified event and give up the CPU until it happens. The
  260.  * null event is special: it means "I don't want to block on an event, but let
  261.  * somebody else run for a while". It can also mean that the present process
  262.  * is terminating; in this case the wait never returns.
  263.  *
  264.  * Pwait() returns 0 if the event was signaled; otherwise it returns the
  265.  * arg in an alert() call. Pwait must not be called from interrupt level.
  266.  */
  267. int
  268. pwait(event)
  269. void *event;
  270. {
  271.     struct proc *oldproc;
  272.     char i_state;
  273.     int tmp;
  274.  
  275.     i_state = dirps();
  276.     if(Curproc != NULLPROC){    /* If process isn't terminating */
  277.         if(Stkchk)
  278.             chkstk();
  279.  
  280.         if(event == NULL){
  281.             /* Special case; just give up the processor.
  282.              *
  283.              * Optimization: if nothing else is ready, just return.
  284.              */
  285.             if(Rdytab == NULLPROC){
  286.                 restore(i_state);
  287.                 return 0;
  288.             }
  289.         } else {
  290.             /* Post a wait for the specified event */
  291.             Curproc->event = event;
  292.             Curproc->state = WAITING;
  293.         }
  294.         addproc(Curproc);
  295.     }
  296.     /* Look for a ready process and run it. If there are none,
  297.      * loop or halt until an interrupt makes something ready.
  298.      */
  299.     while(Rdytab == NULLPROC){
  300.         /* Give system back to upper-level multitasker, if any.
  301.          * Note that this function enables interrupts internally
  302.          * to prevent deadlock, but it restores them (i.e., turns
  303.          * them back off) before returning here.
  304.          */
  305.         giveup();
  306.     }
  307.     /* Remove first entry from ready list */
  308.     oldproc = Curproc;
  309.     Curproc = Rdytab;
  310.     delproc(Curproc);
  311.  
  312.     /* Now do the context switch.
  313.      * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
  314.      *
  315.      * If the old process has gone away, simply load the new process's
  316.      * environment. Otherwise, save the current process's state. Then if
  317.      * this is still the old process, load the new environment. Since the
  318.      * new task will "think" it's returning from the setjmp() with a return
  319.      * value of 1, the comparison with 0 will bypass the longjmp(), which
  320.      * would otherwise cause an infinite loop.
  321.      */
  322. #ifdef    PROCTRACE
  323.     if(strcmp(oldproc->name,Curproc->name) != 0){
  324.           printf("-> %s(%d)\n",Curproc->name,!!Curproc->i_state);
  325.         fflush(stdout);
  326.     }
  327. #endif
  328.     /* Note use of comma operator to save old interrupt state only if
  329.      * oldproc is non-null
  330.      */
  331.     if(oldproc == NULLPROC
  332.      || (oldproc->i_state = i_state, setjmp(oldproc->env) == 0)){
  333.         /* We're still running in the old task; load new task context.
  334.          * The interrupt state is restored here in case longjmp
  335.          * doesn't do it (e.g., systems other than Turbo-C).
  336.          */
  337.         restore(Curproc->i_state);
  338.         longjmp(Curproc->env,1);
  339.     }
  340.     /* At this point, we're running in the newly dispatched task */
  341.     tmp = Curproc->retval;
  342.     Curproc->retval = 0;
  343.  
  344.     /* Also restore the true interrupt state here, in case the longjmp
  345.      * DOES restore the interrupt state saved at the time of the setjmp().
  346.      * This is the case with Turbo-C's setjmp/longjmp.
  347.      */
  348.     restore(Curproc->i_state);
  349.     return tmp;
  350. }
  351.  
  352. /* Make ready the first 'n' processes waiting for a given event. The ready
  353.  * processes will see a return value of 0 from pwait().  Note that they don't
  354.  * actually get control until we explicitly give up the CPU ourselves through
  355.  * a pwait(). Psignal may be called from interrupt level. It returns the
  356.  * number of processes that were woken up.
  357.  */
  358. int
  359. psignal(event,n)
  360. void *event;    /* Event to signal */
  361. int n;        /* Max number of processes to wake up */
  362. {
  363.     register struct proc *pp;
  364.     struct proc *pnext;
  365.     int i_state;
  366.     unsigned int hashval;
  367.     int cnt = 0;
  368.  
  369.     if(Stkchk)
  370.         chkstk();
  371.  
  372.     if(event == NULL)
  373.         return 0;        /* Null events are invalid */
  374.  
  375.     /* n = 0 means "signal everybody waiting for this event" */
  376.     if(n == 0)
  377.         n = 65535;
  378.  
  379.     hashval = phash(event);
  380.     i_state = dirps();
  381.     for(pp = Waittab[hashval];n != 0 && pp != NULLPROC;pp = pnext){
  382.         pnext = pp->next;
  383.         if(pp->event == event){
  384. #ifdef    PROCTRACE
  385.             if(i_state){
  386.                 printf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
  387.                  ptol(pp),pp->name);
  388.                 fflush(stdout);
  389.             }
  390. #endif
  391.             delproc(pp);
  392.             pp->state &= ~WAITING;
  393.             pp->event = 0;
  394.             pp->retval = 0;
  395.             addproc(pp);
  396.             n--;
  397.             cnt++;
  398.         }
  399.     }
  400. #ifdef    SUSPEND_PROC
  401.     for(pp = Susptab;n != 0 && pp != NULLPROC;pp = pnext){
  402.         pnext = pp->next;
  403.         if(pp->event == event){
  404. #ifdef    PROCTRACE
  405.             if(i_state){
  406.                 printf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
  407.                  ptol(pp),pp->name);
  408.                 fflush(stdout);
  409.             }
  410. #endif /* PROCTRACE */
  411.             delproc(pp);
  412.             pp->state &= ~WAITING;
  413.             pp->event = 0;
  414.             pp->retval = 0;
  415.             addproc(pp);
  416.             n--;
  417.             cnt++;
  418.         }
  419.     }
  420. #endif    /* SUSPEND_PROC */
  421.     restore(i_state);
  422.     return cnt;
  423. }
  424.  
  425. /* Rename a process */
  426. void
  427. chname(pp,newname)
  428. struct proc *pp;
  429. char *newname;
  430. {
  431.     free(pp->name);
  432.     pp->name = strdup(newname);
  433. }
  434. /* Remove a process entry from the appropriate table */
  435. static void
  436. delproc(entry)
  437. register struct proc *entry;    /* Pointer to entry */
  438. {
  439.     int i_state;
  440.  
  441.     if(entry == NULLPROC)
  442.         return;
  443.  
  444.     i_state = dirps();
  445.     if(entry->next != NULLPROC)
  446.         entry->next->prev = entry->prev;
  447.     if(entry->prev != NULLPROC){
  448.         entry->prev->next = entry->next;
  449.     } else {
  450.         switch(entry->state){
  451.         case READY:
  452.             Rdytab = entry->next;
  453.             break;
  454.         case WAITING:
  455.             Waittab[phash(entry->event)] = entry->next;
  456.             break;
  457. #ifdef    SUSPEND_PROC
  458.         case SUSPEND:
  459.         case SUSPEND|WAITING:
  460.             Susptab = entry->next;
  461.             break;
  462. #endif
  463.         }
  464.     }
  465.     restore(i_state);
  466. }
  467. /* Append proc entry to end of appropriate list */
  468. static void
  469. addproc(entry)
  470. register struct proc *entry;    /* Pointer to entry */
  471. {
  472.     register struct proc *pp;
  473.     struct proc **head;
  474.     int i_state;
  475.  
  476.     if(entry == NULLPROC)
  477.         return;
  478.  
  479.     switch(entry->state){
  480.     case READY:
  481.         head = &Rdytab;
  482.         break;
  483.     case WAITING:
  484.         head = &Waittab[phash(entry->event)];
  485.         break;
  486. #ifdef    SUSPEND_PROC
  487.     case SUSPEND:
  488.     case SUSPEND|WAITING:
  489.         head = &Susptab;
  490.         break;
  491. #endif
  492.     }
  493.     entry->next = NULLPROC;
  494.     i_state = dirps();
  495.     if(*head == NULLPROC){
  496.         /* Empty list, stick at beginning */
  497.         entry->prev = NULLPROC;
  498.         *head = entry;
  499.     } else {
  500.         /* Find last entry on list */
  501.         for(pp = *head;pp->next != NULLPROC;pp = pp->next)
  502.             ;
  503.         pp->next = entry;
  504.         entry->prev = pp;
  505.     }
  506.     restore(i_state);
  507. }
  508. static unsigned
  509. phash(event)
  510. void *event;
  511. {
  512.     register char *cp = (char *)&event;
  513.     int i = sizeof(event);
  514.     register unsigned x = 0;
  515.  
  516.     while(i-- != 0)
  517.         x ^= *cp++;
  518.  
  519.     return x % PHASH;
  520. }
  521.